#include "GF.h"
#include "poly.h"
#include "decoder_functions.h"
#include "decoder.h"
#include "run_functions.h"
#include "test.h"
#include "encoder_functions.h"
#include "data_gen.h"

char* help_string = "This is the main program help string.\n";

int main(int argc, char **argv) {

    double *pmf; // Double array containing the pmf for error locations.
    int mode;    // Data generation mode.  See data_gen.h for definitions.

    Vector * prim_poly;    // Primitive polynomial for the field
    Matrix * vector_space; // Vector space representation of the field
    Matrix * add_one;      // Add-one table for GF calculations

    // Parse and check the input arguments
    ArgStruct *args;
    int arg_status;

    args = parseArgs(argc, argv);
    arg_status = checkArgs(args);
    if (arg_status == ARG_FAILURE) {
        fprintf(stderr, "Exiting...\n");
        return 0;
    }

    // Check for help string
    if (args->help == 1) {
        // TODO: Write a real help string for this
        printf("This is the program help.\n");
        return 0;
    }

    // Call various system commands, based on input arguments.
    if (args->test == 1) { //Run various function tests
        if (args->verbose) {
            printf("Running function tests...\n");
        }
        runTests(args);
    }

    // Create add-one table
    if (args->verbose) {
        printf("\nCreating add-one table...");
    }
    prim_poly = gf_bin_primpoly(args->m);
    vector_space = gf_vector(args->m, prim_poly);
    add_one = gf_add_one(args->m, vector_space);
    if (args->verbose) {
        printf("Done\n");
    }

    // If data creation is flagged, create data
    if (args->gen_data) {
        if (args->verbose) {
            printf("Generating data...\n");
        }
       
        // Determine the data generation mode
        if (args->e_pmf != NULL) {
            mode = PROB_PER_SYMBOL;
        }
        else {
            mode = FIXED_ERR_PROB;
        } 

        // Parse error probability pmf 
        if (args->e_pmf != NULL) {
            if (args->verbose) {
                printf("Parsing error pmf...");
            }
            pmf = parse_pmf(args->e_pmf, args->m, args->t);
            if (pmf == NULL) {
                fprintf(stderr, "Exiting...\n");
                return 0;
            }
            if (args->verbose) {
                printf("Done\n");
            }
        }

        if (!(create_data(args->m,
                        add_one,
                        args->t,
                        args->data_length,
                        args->e_prob,
                        args->e_per_word,
                        pmf,
                        mode,
                        args->ofile))) {
            fprintf(stderr, "Error: unable to create data file %s.\n", args->ofile);
        }
        
        if (args->verbose) {
            printf("Done\n");
        }
    }

    if (!(args->no_run)) {
        //serialDecoder(args->m, add_one, args->t, "indata_10000_m_3_t_2", "serialData");
        //pthreadsDecoder(args->m, add_one, args->t, args->ifile, args->dfile);
        //openMPDecoder(args->m, add_one, args->t, args->num_DEs, args->ifile, args->dfile); 
    }

    free(args);
    free_vector(prim_poly);
    free_matrix(vector_space);
    free_matrix(add_one);

    return 0;

}

